//////////////////////////////////////////////////////////////////////
// Texture.h
//
// SHEN Fangyang
// me@shenfy.com
//
// Copyright (C) SHEN Fangyang, 2011, All rights reserved.
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
//  Brief Description
//
//	Texture wrappers
//
//////////////////////////////////////////////////////////////////////
#pragma once
#include <BasisObj.h>
#include <D3D10.h>
#include <string>
#include <w32lib_basic.h>
#include <ImgPtr.h>
#include <TextureFormat.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_array.hpp>
#include <vector>

namespace grflib
{
	namespace engine
	{
		namespace core
		{
			//////////////////////////////////////////////////
			//Generic texture
			class CTexture : public IResource, private boost::noncopyable
			{
			public:
				explicit CTexture(void);
				CTexture(TextureSpec::TextureUsage usage,
						 TextureSpec::TextureDimension dim,
						 TextureSpec::BindTarget bindTarget,
						 bool bInitialized = false,
						 DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN);
				virtual ~CTexture(void);

				virtual HRESULT OnCreateDevice(ID3D10Device *pd3dDevice,
					const DXGI_SURFACE_DESC *pBufferSurfaceDesc) = 0;
				virtual void OnDestroy(void);

				//public interface
				ID3D10ShaderResourceView *GetShaderResourceView(void) {return m_pSRView;}
				ID3D10RenderTargetView *GetRenderTargetView(void) {return m_pRenderTargetView;}
				ID3D10DepthStencilView *GetDepthStencilView(void) {return m_pDepthStencilView;}
				TextureSpec::TextureUsage GetTextureUsage(void);
				//ID3D10Resource *GetRawTexture(void) {return m_pTexture;}

				std::size_t GetDimension(std::size_t dim);
                inline bool &UseAutoMipmap(void) {return m_bAutoMipmap;}

				virtual HRESULT CopyFrom(boost::shared_ptr<CTexture> &pSrc) = 0;  //async method

			protected:
				void DestroyResource(void);

			protected:
				TextureSpec::TextureUsage m_usage;
				TextureSpec::TextureDimension m_dimSpec;
				TextureSpec::BindTarget m_bindTarget;

				std::size_t m_dimension[3];
				bool m_bInitialized;
                bool m_bAutoMipmap;

				DXGI_FORMAT m_format;

				ID3D10Resource *m_pTexture;
				ID3D10ShaderResourceView *m_pSRView;
				ID3D10RenderTargetView *m_pRenderTargetView;
				ID3D10DepthStencilView *m_pDepthStencilView;
			};


			////////////////////////////////////////////////////////////////////////////////////////////////////
			class CTexture1D : public CTexture
			{
			public:
				CTexture1D(UINT usage, TextureSpec::BindTarget bindTarget, std::size_t width, DXGI_FORMAT format); //NOT initialized
				CTexture1D(UINT usage, TextureSpec::BindTarget bindTarget, w32lib::ImagePtr imgPtr);
				virtual ~CTexture1D(void);

				virtual HRESULT OnCreateDevice(ID3D10Device *pd3dDevice,
					const DXGI_SURFACE_DESC *pBufferSurfaceDesc);
				virtual void OnDestroy(void);
				virtual HRESULT CopyFrom(boost::shared_ptr<CTexture> &pSrc);  //async method
				HRESULT UpdateGPU(void); //write m_pMemImg to GPU buffer

				HRESULT Resize(std::size_t width, DXGI_FORMAT format);
				std::size_t GetLength(void) {return m_dimension[0];}
				w32lib::ImagePtr &GetMemImage(void) {return m_pMemImg;}

			protected:
				void DestroyResource1D(void);
				CTexture1D(void) {}
				w32lib::ImagePtr m_pMemImg;
                std::vector<w32lib::ImagePtr> m_pMipmaps;
			};


			////////////////////////////////////////////////////////////////////////////////////////////////////
			class CTexture2D : public CTexture
			{
			public:
				CTexture2D(UINT usage, TextureSpec::BindTarget bindTarget, std::size_t width, std::size_t height, DXGI_FORMAT format); //NOT initialized
				CTexture2D(UINT usage, TextureSpec::BindTarget bindTarget, w32lib::ImagePtr imgPtr);
				virtual ~CTexture2D(void);

				virtual HRESULT OnCreateDevice(ID3D10Device *pd3dDevice,
					const DXGI_SURFACE_DESC *pBufferSurfaceDesc);
				virtual void OnDestroy(void);
				virtual HRESULT CopyFrom(boost::shared_ptr<CTexture> &pSrc); //async method
				HRESULT ReadBack(UINT mipLevel);
				HRESULT UpdateGPU(void); //write m_pMemImg to GPU buffer

				HRESULT Resize(std::size_t width, std::size_t height, DXGI_FORMAT format);
				std::size_t GetWidth(void) {return m_dimension[0];}
				std::size_t GetHeight(void) {return m_dimension[1];}
				w32lib::ImagePtr &GetMemImage(void) {return m_pMemImg;}
                inline std::size_t NumChannel(void) {return m_nChannel;}

			protected:
				void DestroyResource2D(void);
				CTexture2D(void) {}
				std::size_t m_nChannel;
				w32lib::ImagePtr m_pMemImg;
                std::vector<w32lib::ImagePtr> m_pMipmaps;
			};


			////////////////////////////////////////////////////////////////////////////////////////////////////
			class CTexture3D : public CTexture
			{
			public:
				CTexture3D(UINT usage, TextureSpec::BindTarget bindTarget,
						   std::size_t dim1, 
						   std::size_t dim2,
						   std::size_t dim3,
						   DXGI_FORMAT format); //NOT initialized
				CTexture3D(UINT usage, TextureSpec::BindTarget bindTarget, 
						   boost::shared_array<char> &initData,
						   std::size_t dim1, 
						   std::size_t dim2, 
						   std::size_t dim3,
						   DXGI_FORMAT format); //initialized
                CTexture3D(UINT usage, TextureSpec::BindTarget bindTarget,
                           w32lib::ImagePtr imgPtr,
                           std::size_t dim2); //dim1 = width, dim3 = height / dim2
				virtual ~CTexture3D(void);

				virtual HRESULT OnCreateDevice(ID3D10Device *pd3dDevice,
					const DXGI_SURFACE_DESC *pBufferSurfaceDesc);
				virtual void OnDestroy(void);
				virtual HRESULT CopyFrom(boost::shared_ptr<CTexture> &pSrc); //async method

				HRESULT Resize(std::size_t dim1, std::size_t dim2, std::size_t dim3, DXGI_FORMAT format);

			protected:
				void DestroyResource3D(void);
				CTexture3D(void) : m_releaseMem(true) {}
				
				boost::shared_array<char> m_data;
				std::size_t m_bpc;
				std::size_t m_nChannel;
				DXGI_FORMAT m_format;
				bool m_isFloat;
                const bool m_releaseMem;
			};


			////////////////////////////////////////////////////////////////////////////////////////////////////
			// Cube texture uses one single w32lib::CImgTmpl with horizontal strip layout
			class CTextureCube : public CTexture
			{
			public:
				CTextureCube(UINT usage, TextureSpec::BindTarget bindTarget, std::size_t faceWidth, std::size_t faceHeight, DXGI_FORMAT format); //NOT initialized
				CTextureCube(UINT usage, TextureSpec::BindTarget bindTarget, w32lib::ImagePtr imgPtr);
				virtual ~CTextureCube(void);

				virtual HRESULT OnCreateDevice(ID3D10Device *pd3dDevice, const DXGI_SURFACE_DESC *pBufferSurfaceDesc);
				virtual void OnDestroy(void);
				virtual HRESULT CopyFrom(boost::shared_ptr<CTexture> &pSrc);
				HRESULT ReadBack(void);
				HRESULT Resize(std::size_t faceWidth, std::size_t faceHeight, DXGI_FORMAT format);
				std::size_t GetFaceWidth(void) {return m_dimension[0];}
				std::size_t GetFaceHeight(void) {return m_dimension[1];}
				w32lib::ImagePtr &GetMemImage(void) {return m_pMemImg;}

			protected:
				void DestroyResourceCube(void);
				CTextureCube(void) {}
				w32lib::ImagePtr m_pMemImg;
			};

		} //namespace core
	} //namespace engine
} //namespace grflib